/*
 * Copyright Hundsun Technologies Inc. All Rights Reserved.
 */

package service

import (
	"context"
	"sync"

	"hundsun.com/hsl/hschain/common/util/pb"
	"hundsun.com/hsl/hschain/module"
	"hundsun.com/hsl/hschain/module/registry"
	"hundsun.com/hsl/hschain/protos"
	"hundsun.com/hsl/hschain/rpc/common/rpcerror"
)

var once sync.Once

// GoroutineErrorWrapper goroutine错误包装
type GoroutineErrorWrapper struct {
	Error        error
	GoroutineTag string
}

type rpcModule struct {
	module.Adapter
	rpcInstance *RPCService
}

// NewRPC 新建一个rpc模块
func NewRPC() module.Module {
	m := &rpcModule{}
	moduleStartupFunc := func(startedInterestedModules map[string][]*registry.ModRegKV) error {
		var err error
		rpcCtx, _ := context.WithCancel(m.RootCtx)
		rpcerror.Init(m.Log)

		errChan := make(chan GoroutineErrorWrapper, 1)

		// 初始化
		p := &RPCService{}
		if err = p.Init(rpcCtx, m, errChan); err != nil {
			return err
		}
		m.rpcInstance = p

		//初始化配置项

		grpcPort := p.rpcConfig.GrpcPort
		JSONRPCPort := p.rpcConfig.JSONRPCPort

		//启动rpc服务端
		if err = p.startRPCServer(grpcPort, JSONRPCPort); err != nil {
			m.Log.Errorf("failed to start rpc server, grpcPort:%s, jsonRpcPort%s, reason:%v", grpcPort, JSONRPCPort, err.Error())
			_, _ = m.Shutdown()
			return err
		}

		//
		go p.procTopicMqMsg()

		m.Log.Infof("module started:%s", p.config.ModuleID)
		return nil
	}

	m.Init(module.RPCModuleName, m.GetInterestedModules(), moduleStartupFunc)
	return m
}

//Shutdown 模块关闭
func (p *rpcModule) Shutdown() (module.Status, error) {
	var err error
	p.Status = module.StatusDown
	//关闭grpc
	err = p.rpcInstance.closeRPCServer()
	if err != nil {
		p.Log.Errorf("close rpc server failed,%v", err)
		p.Status = module.StatusError
	}

	p.Log.Infof("shutdown %s", p.Config.ModuleID)
	p.RootCtxCancelFunc()
	p.Status = module.StatusDown
	return p.Status, nil
}

//GetInterestedModules 获取感兴趣模块
func (p *rpcModule) GetInterestedModules() []string {
	payload := pb.GetGenesisTransactionPayload()
	//是否启用子链代理
	if payload.ChainID == protos.MainChainID {
		return []string{module.P2pModuleName, module.WorkerExecutorModuleName}
	}
	return []string{}
}

//IsMasterStandbyMode IsMasterStandbyMode
func (p *rpcModule) IsMasterStandbyMode() bool {
	return false
}

//IsMaster IsMaster
func (p *rpcModule) IsMaster() bool {
	return false
}

//CompeteMaster CompeteMaster
func (p *rpcModule) CompeteMaster() (bool, error) {
	return false, nil
}

//IsParallel 是否平行链
func (p *rpcModule) IsParallel() bool {
	return !(p.rpcInstance.rpcConfig.ChainID == protos.MainChainID)
}
